namespace NHCodeFirst.FluentMapper
{
    using System;
    using Enums;
    using HbmModel;

    public class AnyMapper<TAny>
    {
        private readonly Any any;

        internal AnyMapper(Any any)
        {
            this.any = any;
        }

        public AnyMapper<TAny> AddMetaValue<TValue>(string value) where TValue : class, TAny
        {
            var type = typeof (TValue);
            var fullName = type.FullName;
            if (fullName != null)
                any.MetaValues.Add(value, fullName);
            return this;
        }

        public AnyMapper<TAny> EntityTypeColumn(string name)
        {
            return EntityTypeColumn(name, null);
        }

        public AnyMapper<TAny> EntityTypeColumn(string name,Action<ColumnMapper> mapper)
        {
            if (any.EntityTypeColumn == null)
                any.EntityTypeColumn = new Column();
            EntityColumnMapper(name, any.EntityTypeColumn, mapper);
            return this;
        }

        public AnyMapper<TAny> EntityIdentifierColumn(string name)
        {
            return EntityIdentifierColumn(name, null);
        }

        public AnyMapper<TAny> EntityIdentifierColumn(string name, Action<ColumnMapper> mapper)
        {
            if (any.EntityIdentifierColumn == null)
                any.EntityIdentifierColumn = new Column();
            EntityColumnMapper(name,any.EntityIdentifierColumn, mapper);
            return this;
        }

        private void EntityColumnMapper(string name, Column column, Action<ColumnMapper> mapper)
        {
            column.Name = name;
            if (mapper != null)
                mapper(new ColumnMapper(column));
        }

        public AnyMapper<TAny> Cascade(AnyCascade value)
        {
            switch (value)
            {
                case AnyCascade.SaveUpdate:
                    any.Cascade = "save-update";
                    break;
                default:
                    any.Cascade = value.ToString().ToLower();
                    break;
            }
            return this;
        }

        public AnyMapper<TAny> Lazy(bool value)
        {
            any.Lazy = value.ToString().ToLower();
            return this;
        }


        public AnyMapper<TAny> IdType<T>()
        {
            return IdType(typeof(T));
        }

        public AnyMapper<TAny> IdType(Type value)
        {
            any.IdType = value.FullName;
            return this;
        }

        public AnyMapper<TAny> MetaType<T>()
        {
            return MetaType(typeof(T));
        }

        public AnyMapper<TAny> MetaType(Type value)
        {
            any.MetaType = value.FullName;
            return this;
        }

        public AnyMapper<TAny> Access(Access access, Naming? namingStrategy = null)
        {
            return Access(access.ToString().ToLower(), namingStrategy);
        }

        public AnyMapper<TAny> Access<T>(Naming? namingStrategy = null)
        {
            return Access(typeof(T).FullName, namingStrategy);
        }

        public AnyMapper<TAny> Access(Type type, Naming? namingStrategy = null)
        {
            return Access(type.FullName, namingStrategy);
        }

        private AnyMapper<TAny> Access(string access, Naming? naming)
        {
            any.Access = access;
            if (naming.HasValue)
                any.Access += "." + EnumsToHbmString.GetAccessNamingStrategy(naming.Value);
            return this;
        }

        public AnyMapper<TAny> Insert(bool value)
        {
            any.Insert = value.ToString().ToLower();
            return this;
        }

        public AnyMapper<TAny> Update(bool value)
        {
            any.Update = value.ToString().ToLower();
            return this;
        }

        public AnyMapper<TAny> OptimisticLock(bool value)
        {
            any.OptimisticLock = value.ToString().ToLower();
            return this;
        }  
    }
}